﻿using System;
using System.Linq;
using Awesome.Extensions.Enumerable;
using Awesome.Extensions.String;

namespace Sandbox
{
    internal class Program
    {
        #region Method OF

        private const string OF_DELEGATE =
            @"[DebuggerStepThrough]
            public static MethodInfo Of<{0}>(Action<{0}> a)
            {{
               return   MethodInfoProvider.FromDelegate(a);
            }}";

        private const string OF_INSTANCE =
            @"[DebuggerStepThrough]
            public static MethodInfo Of<TClass, {0}>(Expression<Func<TClass, Action<{0}>>> e)
            {{
                return  MethodInfoProvider.FromExpression(e);
            }}";

        private const string OF_RESULT_DELEGATE =
            @"[DebuggerStepThrough]
            public static MethodInfo Of<{0}>(Func<{0}, TResult> f)
            {{
                return MethodInfoProvider.FromDelegate(f);
            }}";

        private const string OF_RESULT_INSTANCE =
            @"[DebuggerStepThrough]
            public static MethodInfo Of<TClass, {0}>(Expression<Func<TClass, Func<{0}, TResult>>> e)
            {{
                return  MethodInfoProvider.FromExpression(e);
            }}";


        private static string CreateTypeArgs(string pattern, int count)
        {
            return String.Format(pattern, IE.Range(1, count).Select(i => "T" + i).Glue(", "));
        }

        private static string CreateTypeofs(string pattern, int count)
        {
            return String.Format(pattern, IE.Range(1, count).Select(i => "T" + i).Glue(", "),
                                 IE.Range(1, count).Select(i => "typeof(T" + i + ")").Glue(", "));
        }



        private static void GenerateMethodOf()
        {
            Func<string, string> methods = pattern => IE.Range(0, 16)
                                                          .Select(c => CreateTypeArgs(pattern, c))
                                                          .Glue(Environment.NewLine);


            var code = (methods(OF_DELEGATE)
                        + methods(OF_INSTANCE)
                        + methods(OF_RESULT_DELEGATE)
                        + methods(OF_RESULT_INSTANCE));

            code.SetClipboard();
        }

        #endregion
        #region GetMethod
        private const string GET_METHOD =
            @"public static MethodInfo GetMethod<{0}>(this Type type, string name,
                BindingFlags flags = BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static)
            {{
                return type.GetMethod(name, flags, null, new[] {{ {1} }}, null);
            }}";

        private static void GenerateGetMethod()
        {
            Func<string, string> methods = pattern => IE.Range(0, 16)
                                                          .Select(c => CreateTypeofs(pattern, c))
                                                          .Glue(Environment.NewLine);


            var code = (methods(GET_METHOD));

            code.SetClipboard();
        }
#endregion

        private class AnonymousType
        {
            public static AnonymousType<T> Create<T>(T template)
            {
                return new AnonymousType<T>(template);
            }
        }

        private class AnonymousType<T>
        {
            private readonly T _template;

            public AnonymousType(T template)
            {
                _template = template;
            }

            public T CreateInstance()
            {
                return _template;
            }
        }

        [STAThread]
        private static void Main(string[] args)
        {
            GenerateMethodOf();
        }
    }
}